﻿using Mapster;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Zhp.Auth.IService;
using Zhp.Auth.Model;
using Zhp.Cache;
using Zhp.Common.Appsetting;
using Zhp.Common.Extention;
using Zhp.Common.Helper;
using Zhp.Common.WebApp;

namespace Zhp.Auth.Service
{
    public class OnlineService : IOnlineService
    {
        private readonly ICacheService _cache;

        public OnlineService(ICacheService cacheService, IConfiguration configuration)
        {
            _cache = cacheService;
        }

        /// <summary>
        /// 查询登录用户
        /// </summary>
        /// <returns></returns>
        public List<OnlineUserViewModel> GetOnlineUserList(OnlineUserQuery query)
        {
            RemoveExpiresOnlineUser();

            var list = _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineUser).ToList();

            var options = AppSettingHelper.GetOptions<SysDataOptions>();
            Func<OnlineUserModel, bool> func = (x) => string.IsNullOrEmpty(query.CreateByName) || x.UserName == query.CreateByName;

            list = list.Where(x => x.UserCode != options.DefaultRootUser).Where(func).ToList();

            query.TotalCount = list.Count;
            //分页
            list = list.OrderByDescending(x => x.CreateTime).Skip((query.PageIndex - 1) * query.PageSize).Take(query.PageSize).ToList();

            var result = list.Adapt<List<OnlineUserViewModel>>();

            foreach (var item in result)
            {
                item.AccessExpiresTime = GetAccessExpiresDate(item.CreateTime);
                item.RefreshExpiresTime = GetRefreshExpiresDate(item.CreateTime);
                item.TokenTypeName = item.TokenType.GetDescription();
                //item.CompanyName = item.CompanyCode.GetEnumDescription<LanguageEnum>();
            }

            return result;
        }

        public List<OnlineUserModel> GetOnlineActiveUserList()
        {
            return _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineActiveUser);
        }

        /// <summary>
        /// 判断用户是否登录
        /// </summary>
        /// <param name="cacheId"></param>
        /// <param name="refreshTokenId"></param>
        /// <returns></returns>
        public IsOnlineInfo IsRefreshOnline(string cacheId, string refreshTokenId)
        {
            IsOnlineInfo isOnlineInfo = new IsOnlineInfo { IsOnline = false };

            var forcedOfflineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.ForcedOfflineUser, refreshTokenId);
            if (forcedOfflineUser != null)
            {
                RemoveOfflineUser(refreshTokenId);

                isOnlineInfo.Message = "您的账号被系统强制登出！";
                return isOnlineInfo;
            }

            var otherDeviceUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OtherDeviceOfflineUser, refreshTokenId);
            if (otherDeviceUser != null)
            {
                RemoveOfflineUser(refreshTokenId);

                isOnlineInfo.Message = "被迫下线，当前账号已在其他客户端登录！";
                return isOnlineInfo;
            }

            var onlineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, cacheId);
            if (onlineUser == null)
            {
                isOnlineInfo.Message = "登录过期，请重新登录！";
                return isOnlineInfo;
            }

            isOnlineInfo.IsOnline = true;
            isOnlineInfo.CurrentUserInfo = onlineUser;
            return isOnlineInfo;
        }

        public IsOnlineInfo IsAccessOnline(string cacheId, string refreshTokenId)
        {
            IsOnlineInfo isOnlineInfo = new IsOnlineInfo { IsOnline = false };

            var forcedOfflineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.ForcedOfflineUser, refreshTokenId);
            if (forcedOfflineUser != null)
            {
                RemoveOfflineUser(refreshTokenId);

                isOnlineInfo.Message = "您的账号被系统强制登出！";
                return isOnlineInfo;
            }

            var otherDeviceUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OtherDeviceOfflineUser, refreshTokenId);
            if (otherDeviceUser != null)
            {
                RemoveOfflineUser(refreshTokenId);

                isOnlineInfo.Message = "被迫下线，当前账号已在其他客户端登录！";
                return isOnlineInfo;
            }

            var onlineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, cacheId);
            if (onlineUser == null)
            {
                isOnlineInfo.Message = "登录过期，请重新登录！";
                return isOnlineInfo;
            }

            isOnlineInfo.IsOnline = true;
            isOnlineInfo.CurrentUserInfo = onlineUser;
            return isOnlineInfo;
        }

        /// <summary>
        /// 获取当前用户
        /// </summary>
        /// <param name="onlineId"></param>
        /// <returns></returns>
        /// <exception cref="SecurityTokenInvalidLifetimeException"></exception>
        public OnlineUserModel GetOnlineUser(string cacheId)
        {
            var onlineUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, cacheId);
            if (onlineUser != null)
            {
                return onlineUser;
            }
            else
            {
                var result = new
                {
                    Status = StatusCodeConst.AuthRefreshTokenStatusCode,
                    Message = StatusCodeConst.AuthRefreshTokenMessage
                };
                throw new SecurityTokenInvalidLifetimeException(result.ToJson());
            }
        }

        /// <summary>
        /// 添加登录用户
        /// </summary>
        /// <param name="onlineUser"></param>
        public void AddOnlineUser(OnlineUserModel onlineUser)
        {
            RemoveExpiresOnlineUser();

            if (!IsMultiClientLogin())
            {
                MoveToOtherDeviceOfflineUser(onlineUser.CacheId);
            }
            _cache.HashListSet(CacheKey.OnlineUser, x => x.CacheId, onlineUser, onlineUser.RefreshExpiresTime - onlineUser.CreateTime);
        }

        /// <summary>
        /// 移除登录用户
        /// </summary>
        /// <param name="cacheId"></param>
        public void RemoveOnlineUser(string cacheId)
        {
            _cache.HashListDelete(CacheKey.OnlineUser, cacheId);
        }

        /// <summary>
        /// 移除强退用户
        /// </summary>
        /// <param name="onlineId"></param>
        public void ForcedRemoveOfflineUser(string cacheId)
        {
            var lastLoginUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, cacheId);
            if (lastLoginUser != null)
            {
                _cache.HashListDelete(CacheKey.OnlineUser, cacheId);
                _cache.HashListSet(CacheKey.ForcedOfflineUser, x => x.RefreshTokenId, lastLoginUser);
            }
        }

        /// <summary>
        /// 异地设备登录账号时，将已登录的数据移动到缓存用于提示用户
        /// </summary>
        /// <param name="onlineId"></param>
        private void MoveToOtherDeviceOfflineUser(string cacheId)
        {
            var lastLoginUser = _cache.HashListGet<OnlineUserModel>(CacheKey.OnlineUser, cacheId);
            if (lastLoginUser != null)
            {
                _cache.HashListDelete(CacheKey.OnlineUser, lastLoginUser.CacheId);
                _cache.HashListSet(CacheKey.OtherDeviceOfflineUser, x => x.RefreshTokenId, lastLoginUser);
            }
        }

        /// <summary>
        /// 移除异地设备登录用户缓存数据和移除强退用户缓存数据
        /// </summary>
        /// <param name="refreshTokenId"></param>
        private void RemoveOfflineUser(string refreshTokenId)
        {
            _cache.HashListDelete(CacheKey.OtherDeviceOfflineUser, refreshTokenId);
            _cache.HashListDelete(CacheKey.ForcedOfflineUser, refreshTokenId);
        }

        /// <summary>
        /// 清理过期用户
        /// </summary>
        private void RemoveExpiresOnlineUser()
        {
            //由于缓存没有过期时间，需要把过期的token删除掉
            var onlineUserList = _cache.HashListGetAll<OnlineUserModel>(CacheKey.OnlineUser);
            var removeList = onlineUserList.Where(x => GetRefreshExpiresDate(x.CreateTime) <= DateTime.Now).Select(x => x.CacheId).ToList();
            foreach (var item in removeList)
            {
                _cache.HashListDelete(CacheKey.OnlineUser, item);
            }
        }

        /// <summary>
        /// 是否多客户端登录
        /// </summary>
        /// <returns></returns>
        public bool IsMultiClientLogin()
        {
            var options = AppSettingHelper.GetOptions<SysDataOptions>();
            return options.MultiClientLogin;
        }

        /// <summary>
        /// 获取AccessToken过期时间
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public DateTime GetAccessExpiresDate(DateTime dateTime)
        {
            var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
            return dateTime.AddMinutes(jwtOptions.Expires);
        }

        /// <summary>
        /// 获取RefreshToken过期时间
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public DateTime GetRefreshExpiresDate(DateTime dateTime)
        {
            var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
            return dateTime.AddMinutes(jwtOptions.RefreshExpires);
        }
    }
}
